package com.nanyang.tms.manager.company.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
import com.alipay.easysdk.kernel.util.ResponseChecker;
import com.alipay.easysdk.payment.common.models.AlipayTradeQueryResponse;
import com.alipay.easysdk.payment.facetoface.models.AlipayTradePrecreateResponse;
import com.nanyang.common.core.annotation.SystemLog;
import com.nanyang.common.core.page.PageBean;
import com.nanyang.common.core.page.PageTableBean;
import com.nanyang.common.tool.utils.string.StringUtil;
import com.nanyang.common.tool.utils.uuid.GlobalIdGeneratorUtil;
import com.nanyang.tms.common.config.AliPayConfig;
import com.nanyang.tms.common.config.TmsConfig;
import com.nanyang.tms.common.contstant.TmsCommonConsts;
import com.nanyang.tms.common.contstant.TmsSerializeConstant;
import com.nanyang.tms.common.dict.TmsCommonEnum;
import com.nanyang.tms.common.dict.TmsExceptionEnum;
import com.nanyang.tms.common.dict.TmsOrderExceptionEnum;
import com.nanyang.tms.common.dict.TmsOrderStateEnum;
import com.nanyang.tms.common.exception.TmsManagerException;
import com.nanyang.tms.common.util.TmsExceptionUtil;
import com.nanyang.tms.dao.company.CompanyDao;
import com.nanyang.tms.dao.company.CompanyRechargeDao;
import com.nanyang.tms.dao.company.CompanyStoredDao;
import com.nanyang.tms.dao.company.CompanyTransactionRecordDao;
import com.nanyang.tms.domain.company.*;
import com.nanyang.tms.domain.company.notify.ALiPayNotifyDO;
import com.nanyang.tms.manager.company.CompanyRechargeManager;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.redisson.codec.JsonJacksonCodec;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Component("companyRechargeManager")
public class CompanyRechargeManagerImpl implements CompanyRechargeManager {
    @Autowired
    private CompanyRechargeDao companyRechargeDao;
    @Autowired
    private GlobalIdGeneratorUtil globalIdGeneratorUtil;
    @Autowired
    private CompanyStoredDao companyStoredDao;
    @Autowired
    private CompanyTransactionRecordDao companyTransactionRecordDao;
    @Autowired
    private CompanyDao companyDao;
    @Autowired
    private AliPayConfig aliPayConfig;
    @Autowired
    private TmsConfig tmsConfig;
    @Autowired
    private RedissonClient redissonClient;
    @Override
    public PageBean<CompanyRechargeVO> listCompanyRecharge(CompanyRechargeQuery query) {
        try {
            if (query == null) {
                log.error(TmsCommonEnum.PARAM_IS_NULL.getCode() + TmsCommonEnum.PARAM_IS_NULL.getMessage());
                throw new TmsManagerException(TmsCommonEnum.PARAM_IS_NULL.getCode() ,TmsCommonEnum.PARAM_IS_NULL.getMessage());
            }
            Integer count = companyRechargeDao.countRecharge(query);
            PageBean<CompanyRechargeVO> page = new PageTableBean<CompanyRechargeVO>(query.getPageIndex(), query.getPageSize());
            if (null != count && count != 0) {
                page.setTotalItem(count);
                int startRow = page.getStartRow();
                if (startRow > 0) {
                    startRow -= 1;
                }
                query.setStartRow(startRow);
                page.addAll(companyRechargeDao.listRecharge(query));
            }
            return page;
        } catch (Exception e) {
            throw TmsExceptionUtil.wrapException(e);
        }
    }

    /**
     * 先看有没有充值
     * @param companyRechargeDO
     */
    @SystemLog(module =SystemLog.Module.STORED,template="storePay")
    @Override
    @Transactional
    public CompanyRechargeVO save(CompanyRechargeDO companyRechargeDO) {
        try {
            CompanyStoredVO companyStoredVO = companyStoredDao.selectByCode(companyRechargeDO.getCompanyCode());
            if(ObjectUtil.isNull(companyStoredVO)){
                log.error(TmsExceptionEnum.COMPANY_STORE_FAIL.getCode() + TmsExceptionEnum.COMPANY_STORE_FAIL.getMessage());
                throw new TmsManagerException(TmsExceptionEnum.COMPANY_STORE_FAIL.getCode() ,TmsExceptionEnum.COMPANY_STORE_FAIL.getMessage());
            }

            String nextSeq = TmsSerializeConstant.COMPANYRECHARGE_KEY+globalIdGeneratorUtil.getNextSeq(TmsSerializeConstant.COMPANYRECHARGE_SEQ_KEY, TmsSerializeConstant.SEQ_INCRBY);
            String qrCodeLink ="";
            if(companyRechargeDO.getTransType()==1){//支付宝支付
                AlipayTradePrecreateResponse alipayTradePrecreateResponse = sendAliPayApply(nextSeq, companyRechargeDO.getAmount().toString());
                //发起支付失败
                if (!ResponseChecker.success(alipayTradePrecreateResponse)) {
                    throw new TmsManagerException(TmsExceptionEnum.CURRENT_ORDER_PAY_ERROR.getCode(), String.format(TmsExceptionEnum.CURRENT_ORDER_PAY_ERROR.getMessage(),alipayTradePrecreateResponse.msg  +","+ alipayTradePrecreateResponse.subMsg));
                }
                qrCodeLink =alipayTradePrecreateResponse.getQrCode();
            }else if(companyRechargeDO.getTransType()==0){//微信支付

            }
            companyRechargeDO.setOrderUrl(qrCodeLink);
            companyRechargeDO.setCompanyName(companyDao.selectByCode(companyRechargeDO.getCompanyCode()).getCompanyName());
            companyRechargeDO.setCardNo(companyStoredVO.getCardNo());
            companyRechargeDO.setUserName(companyStoredVO.getUserName());
            companyRechargeDO.setRechargeCode(nextSeq);
            companyRechargeDao.insert(companyRechargeDO);

            //保存订单号和订单状态到redis
            RMap<String, Integer> redissonClientMap = redissonClient.getMap(TmsCommonConsts.PAYMENT_ORDER_CODE, new JsonJacksonCodec());
            redissonClientMap.put(nextSeq, TmsOrderStateEnum.PAY_ING.getCode());
            CompanyRechargeVO companyRechargeVO = new CompanyRechargeVO();
            companyRechargeVO.setRechargeCode(nextSeq);
            companyRechargeVO.setOrderUrl(qrCodeLink);
            companyRechargeVO.setTransType(companyRechargeDO.getTransType());
            return companyRechargeVO;
        } catch (TmsManagerException e) {
            throw TmsExceptionUtil.wrapException(e);
        }
    }
    /**
     * 发送支付宝支付申请
     */
    private AlipayTradePrecreateResponse sendAliPayApply(String orderCode, String price) {
        try {
            Factory.setOptions(getAliPayOptions());
            Map<String, String> extendParams = new HashMap<>();
            extendParams.put("sys_service_provider_id", aliPayConfig.getSysServiceProviderId());
            return Factory.Payment.FaceToFace()
                    .asyncNotify(aliPayConfig.getNotifyUrl())
                    .optional("extend_params", extendParams)
                    .preCreate(new String(tmsConfig.getProductDesc().getBytes(), StandardCharsets.UTF_8), orderCode, price);
        } catch (Exception e) {
            throw TmsExceptionUtil.wrapException(e);
        }
    }
    /**
     * 获取阿里支付配置文件
     */
    private Config getAliPayOptions() {
        try {
            Config config = new Config();
            config.protocol = "https";
            config.gatewayHost = aliPayConfig.getGateWay();
            config.signType = "RSA2";
            config.appId = aliPayConfig.getAppId();
            // 为避免私钥随源码泄露，推荐从文件中读取私钥字符串而不是写入源码中
            config.merchantPrivateKey = aliPayConfig.getMerchantPrivateKey();
            //注：如果采用非证书模式，则无需赋值上面的三个证书路径，改为赋值如下的支付宝公钥字符串即可
            config.alipayPublicKey = aliPayConfig.getAlipayPublicKey();
            return config;
        } catch (Exception e) {
            throw TmsExceptionUtil.wrapException(e);
        }
    }

    @Override
    public Integer queryOrderState(String orderCode) {
        try {
            RMap<String, Integer> redissonClientMap = redissonClient.getMap(TmsCommonConsts.PAYMENT_ORDER_CODE, new JsonJacksonCodec());
            return redissonClientMap.get(orderCode);
        } catch (Exception e) {
            throw TmsExceptionUtil.wrapException(e);
        }
    }

    @Override
    @Transactional
    public void scanAliPayCallBack(Map<String, String> alipayRequest) {
        try {
            Factory.setOptions(getAliPayOptions());
            Boolean verifyNotify = Factory.Payment.Common().verifyNotify(alipayRequest);
            if (!verifyNotify) {
                throw new TmsManagerException(TmsOrderExceptionEnum.ALI_PAY_AUTH_NOT_PASS.getCode(),TmsOrderExceptionEnum.ALI_PAY_AUTH_NOT_PASS.getMessage());
            }
            ALiPayNotifyDO aLiPayNotifyDO = JSON.parseObject(JSON.toJSONString(alipayRequest), ALiPayNotifyDO.class);
            log.info("支付宝支付返回的结果是:" + JSON.toJSONString(aLiPayNotifyDO));
            //等待交易
            if (aLiPayNotifyDO.getTrade_status().equals(TmsCommonConsts.WAIT_BUYER_PAY)) {
                throw new TmsManagerException(TmsOrderExceptionEnum.WAIT_USER_A_LI_PAY.getCode(),TmsOrderExceptionEnum.WAIT_USER_A_LI_PAY.getMessage());
            }
            //交易完成
            if (aLiPayNotifyDO.getTrade_status().equals(TmsCommonConsts.TRADE_FINISHED)) {
                throw new TmsManagerException(TmsOrderExceptionEnum.A_LI_PAY_FINISH.getCode(),TmsOrderExceptionEnum.A_LI_PAY_FINISH.getMessage());
            }
            //查询订单的真实状态
            AlipayTradeQueryResponse alipayTradeQueryResponse = Factory.Payment.Common().query(aLiPayNotifyDO.getOut_trade_no());
            if (!StringUtil.equals(alipayTradeQueryResponse.tradeStatus, TmsCommonConsts.TRADE_SUCCESS)) {
                throw new TmsManagerException(TmsOrderExceptionEnum.ALI_PAY_NOT_SUCCESS.getCode(),TmsOrderExceptionEnum.ALI_PAY_NOT_SUCCESS.getMessage());
            }
            completePay(aLiPayNotifyDO.getOut_trade_no(), aLiPayNotifyDO.getTrade_no());
            //更新redis中的订单状态
            RMap<String, Integer> redissonClientMap = redissonClient.getMap(TmsCommonConsts.PAYMENT_ORDER_CODE, new JsonJacksonCodec());
            redissonClientMap.replace(aLiPayNotifyDO.getOut_trade_no(), TmsOrderStateEnum.PAY_SUCCESS.getCode());
        } catch (Exception e) {
            throw TmsExceptionUtil.wrapException(e);
        }
    }


    private void completePay(String orderCode, String transCode){
        try {
            //查询出订单
            CompanyRechargeVO companyRechargeVO = companyRechargeDao.selectByCode(orderCode);
            //订单为空
            if (companyRechargeVO == null) {
                throw new TmsManagerException(TmsOrderExceptionEnum.CURRENT_ORDER_NOT_EXIST.getCode(),TmsOrderExceptionEnum.CURRENT_ORDER_NOT_EXIST.getMessage());
            }
            //查询流水记录 不为空 说明已经支付过
            if (StringUtils.isNotEmpty(companyRechargeVO.getTransCode())) {
                throw new TmsManagerException(TmsOrderExceptionEnum.ORDER_AL_PAYED.getCode(),TmsOrderExceptionEnum.ORDER_AL_PAYED.getMessage());
            }
            //订单支付成功
            if (companyRechargeVO.getState().equals(TmsOrderStateEnum.PAY_SUCCESS.getCode())) {
                throw new TmsManagerException(TmsOrderExceptionEnum.ORDER_AL_PAYED.getCode(),TmsOrderExceptionEnum.ORDER_AL_PAYED.getMessage());
            }
            //订单支付已失败
            if (companyRechargeVO.getState().equals(TmsOrderStateEnum.PAY_FAIL.getCode())) {
                throw new TmsManagerException(TmsOrderExceptionEnum.ORDER_AL_PAY_FAIL.getCode(),TmsOrderExceptionEnum.ORDER_AL_PAY_FAIL.getMessage());
            }
            CompanyRechargeDO companyRechargeDO = new CompanyRechargeDO();
            companyRechargeDO.setTransCode(transCode);
            companyRechargeDO.setRechargeCode(orderCode);
            companyRechargeDO.setCompanyCode(companyRechargeVO.getCompanyCode());
            if(companyRechargeDao.updateSuccess(companyRechargeDO)<=0){
                throw new TmsManagerException(TmsOrderExceptionEnum.ORDER_AL_PAYED.getCode(),TmsOrderExceptionEnum.ORDER_AL_PAYED.getMessage());
            };
            CompanyStoredDO companyStoredDO=new CompanyStoredDO();
            companyStoredDO.setUseBalance(companyRechargeVO.getAmount());
            companyStoredDO.setGmtModifiedPin(companyRechargeVO.getGmtModifiedPin());
            companyStoredDO.setCompanyCode(companyRechargeVO.getCompanyCode());
            if(companyStoredDao.updateBalanceAmount(companyStoredDO)<=0){//修改客户储值余额
                throw new TmsManagerException(TmsExceptionEnum.RECHARGE_AMOUNT_ERROR.getCode(), TmsExceptionEnum.RECHARGE_AMOUNT_ERROR.getMessage());
            }
            CompanyStoredVO companyStored = companyStoredDao.getCompanyStored(companyRechargeVO.getCompanyCode());
            if(companyStored == null){
                throw new TmsManagerException(TmsExceptionEnum.COMPANY_STORE_IS_NOT_EXIST.getCode(), TmsExceptionEnum.COMPANY_STORE_IS_NOT_EXIST.getMessage());
            }
            CompanyTransactionRecordDO companyTransactionRecordDO=new CompanyTransactionRecordDO();
            String recordCode= TmsSerializeConstant.COMPANYADTRANSACTION_KEY+globalIdGeneratorUtil.getNextSeq(TmsSerializeConstant.COMPANYADTRANSACTION_SEQ_KEY, TmsSerializeConstant.SEQ_INCRBY);
            companyTransactionRecordDO.setRecordCode(recordCode);
            companyTransactionRecordDO.setBillTypeCode("RECHARGE");
            companyTransactionRecordDO.setBillTypeName("充值");
            companyTransactionRecordDO.setBillCode(transCode);
            companyTransactionRecordDO.setCardNo(companyStored.getCardNo());
            companyTransactionRecordDO.setCardName(companyStored.getCardName());
            companyTransactionRecordDO.setAmountType(0);
            companyTransactionRecordDO.setAmount(companyRechargeVO.getAmount());
            companyTransactionRecordDO.setActualBalance(companyStored.getActualBalance());
            companyTransactionRecordDO.setUseBalance(companyStored.getUseBalance());
            companyTransactionRecordDO.setFrozenAmount(companyStored.getFrozenAmount());
            companyTransactionRecordDO.setPin(companyStored.getPin());
            companyTransactionRecordDO.setUserName(companyStored.getUserName());
            companyTransactionRecordDO.setCompanyCode(companyStored.getCompanyCode());
            companyTransactionRecordDO.setCompanyName(companyDao.selectByCode(companyStored.getCompanyCode()).getCompanyName());
            companyTransactionRecordDO.setIp(companyStored.getIp());
            companyTransactionRecordDO.setGmtCreatePin(companyStored.getPin());
            companyTransactionRecordDao.insert(companyTransactionRecordDO);//添加交易明细
        } catch (TmsManagerException e) {
            throw TmsExceptionUtil.wrapException(e);
        }
    }
}
